package com.learn.datatype.learndate.unsafe;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

/**
 * 功能：日期时间工具（线程不安全）
 *
 * @author wsh
 * @date 2020/9/11
 */
public class DateTimeUtil {
    public static final String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
    public static final String MINUTE_PATTERN = "yyyy-MM-dd HH:mm";
    public static final String HOUR_PATTERN = "yyyy-MM-dd HH:mm:ss";
    public static final String DATE_PATTERN = "yyyy-MM-dd";
    public static final String MONTH_PATTERN = "yyyy-MM";
    public static final String YEAR_PATTERN = "yyyy";
    public static final String MINUTE_ONLY_PATTERN = "mm";
    public static final String HOUR_ONLY_PATTERN = "HH";

    private static final int MILLISECOND_PER_SECOND = 1000;
    private static final int SECOND_PER_MINUTE = 60;
    private static final int MINUTE_PER_HOUR = 60;
    private static final int HOUR_PER_DAY = 24;
    private static final int SECOND_PER_DAY = 86400;
    private static final long MILLISECOND_PER_DAY = 86400000L;
    // 尽量不要算较大的时间，误差会较大
    private static final int DAY_PER_MONTH = 30;
    private static final int DAY_PER_YEAR = 365;


    /**
     * 功能：获取当前日期
     *
     * @return 默认格式，如“Sun Sep 13 00:07:30 CST 2020”
     * @author wsh
     * @date 2020/9/13
     */
    public static Date getCurrentCalendar() {
        Calendar calendar = Calendar.getInstance();
        return calendar.getTime();
    }

    /**
     * 功能：获取当前日期
     *
     * @return 格式：yyyy-MM-dd（如2010-04-24）
     * @author wsh
     * @date 2020/9/13
     */
    public static String getCurrentDate() {
        Calendar calendar = Calendar.getInstance();
        StringBuffer sb = new StringBuffer();
        sb.append(calendar.get(Calendar.YEAR)).append("-");
        sb.append(calendar.get(Calendar.MONTH) + 1).append("-");
        sb.append(calendar.get(Calendar.DAY_OF_MONTH));
        return sb.toString();
    }

    /**
     * 功能：把字符形式的日期转换成Date类型
     *
     * @param dateStr 格式：yyyy-MM-dd
     * @return
     * @author wsh
     * @date 2020/9/13
     */
    public static Date stringToDate(String dateStr) {
        DateFormat format = new SimpleDateFormat(DATE_PATTERN);
        try {
            return format.parse(dateStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 功能：把日期转换为指定的格式
     *
     * @param date    要转换的日期
     * @param pattern 转换的格式
     * @return
     * @author wsh
     * @date 2020/9/13
     */
    public static String dateToString(Date date, String pattern) {
        if (pattern == null || pattern.trim().length() == 0) {
            return null;
        }

        DateFormat format = new SimpleDateFormat(pattern);
        return format.format(date);
    }

    /**
     * 功能：将日期转换为字符串
     *
     * @param date
     * @return 格式：yyyy-MM-dd HH:mm:ss
     * @author wsh
     * @date 2020/9/13
     */
    public static String dateToString(Date date) {
        DateFormat format = new SimpleDateFormat(DATE_TIME_PATTERN);
        return format.format(date);
    }

    /**
     * 功能：本周一
     *
     * @return
     * @author wsh
     * @date 2020/9/13
     */
    public static Date getThisMonday() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
        return calendar.getTime();
    }

    /**
     * 功能：获取当前日期与本周周日之间相差的天数
     *
     * @return
     * @author wsh
     * @date 2020/9/13
     */
    public static int getCurrentPlus() {
        Calendar calendar = Calendar.getInstance();
        // Java 默认周日为一周的第一天
        int days = calendar.get(Calendar.DAY_OF_WEEK);
        // 中国是将星期一作为一周的第一天,所以这里减1
        days = days - 1;
        return 7 - days;
    }

    /**
     * 功能：本周日
     *
     * @return
     * @author wsh
     * @date 2020/9/13
     */
    public static Date getThisSunday() {
        Calendar calendar = Calendar.getInstance();
        // 把当前日期的DATE加上当前日期与本周日之间相差的天数
        calendar.add(Calendar.DATE, getCurrentPlus());
        return calendar.getTime();
    }

    /**
     * 功能：时间计算，对指定单位做加/减运算
     *
     * @param startDate 开始时间，Null 则返回当前时间
     * @param unit      时间单位，支持年y、月M、日d、时H、分m、秒s
     * @param value     时间值
     * @return
     * @author wsh
     * @date 2020/9/14
     */
    public static Date dateTimeCalculate(Date startDate, char unit, int value) {
        if (startDate == null) {
            startDate = new Date();
        }

        Calendar c = Calendar.getInstance();
        c.setTime(startDate);
        switch (unit) {
            case 'y':
                c.set(Calendar.YEAR, c.get(Calendar.YEAR) + value);
                break;
            case 'M':
                c.set(Calendar.MONTH, c.get(Calendar.MONTH) + value);
                break;
            case 'd':
                c.set(Calendar.DATE, c.get(Calendar.DATE) + value);
                break;
            case 'H':
                c.set(Calendar.HOUR, c.get(Calendar.HOUR) + value);
                break;
            case 'm':
                c.set(Calendar.MINUTE, c.get(Calendar.MINUTE) + value);
                break;
            case 's':
                c.set(Calendar.SECOND, c.get(Calendar.SECOND) + value);
                break;
            default:
                break;
        }
        return c.getTime();
    }

    /**
     * 功能：时间比较
     *
     * @param myDate
     * @param compareDate
     * @return myDate>compareDate返回1，<返回-1，相等返回0
     * @author wsh
     * @date 2020/9/14
     */
    public static int dateCompare(Date myDate, Date compareDate) {
        Calendar myCal = Calendar.getInstance();
        myCal.setTime(myDate);

        Calendar compareCal = Calendar.getInstance();
        compareCal.setTime(compareDate);
        return myCal.compareTo(compareCal);
    }

    /**
     * 功能：获取两个日期（不含时分秒）相差的天数，不包含今天
     *
     * @param startDate 开始日期
     * @param endDate   结束日期（一定要大于等于开始日期）
     * @return
     * @author wsh
     * @date 2020/9/14
     */
    public static int dateBetween(Date startDate, Date endDate) throws ParseException {
        Date dateStart = stringToDate(dateToString(startDate, DATE_PATTERN));
        Date dateEnd = stringToDate(dateToString(endDate, DATE_PATTERN));
        long diffMillisecond = dateEnd.getTime() - dateStart.getTime();
        return (int) (diffMillisecond / MILLISECOND_PER_DAY);
    }

    /**
     * 功能：获取日期时间的年份，如2020-09-14，返回 2020
     *
     * @param date
     * @return
     * @author wsh
     * @date 2020/9/14
     */
    public static int getYear(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.YEAR);
    }

    /**
     * 功能：获取日期时间的月份，如2020-09-14，返回 9
     *
     * @param date
     * @return
     * @author wsh
     * @date 2020/9/14
     */
    public static int getMonth(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.MONTH) + 1;
    }

    /**
     * 功能：获取日期时间的第几天（即返回日期的dd），如2020-09-14，返回 14
     *
     * @param date
     * @return
     * @author wsh
     * @date 2020/9/14
     */
    public static int getDate(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.DATE);
    }

    /**
     * 功能：获取日期时间当月的总天数，如2020-09-14，返回 30
     *
     * @param date
     * @return
     * @author wsh
     * @date 2020/9/14
     */
    public static int getDaysOfMonth(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.getActualMaximum(Calendar.DATE);
    }

    /**
     * 功能：获取日期时间当年的总天数，如2020-09-14，返回2020年的总天数
     *
     * @param date
     * @return
     * @author wsh
     * @date 2020/9/14
     */
    public static int getDaysOfYear(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.getActualMaximum(Calendar.DAY_OF_YEAR);
    }

    /**
     * 功能：取当月第一天
     *
     * @param date
     * @return
     * @author wsh
     * @date 2020/9/14
     */
    public static Date getFirstDayOfMonth(Date date) throws Exception {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int value = cal.getActualMinimum(Calendar.DATE);
        return stringToDate(dateToString(date, MONTH_PATTERN) + "-" + value);
    }

    /**
     * 功能：取当月最后一天
     *
     * @param date
     * @return 闰年 2 月返回 29 天，平年 2 月返回 28 天
     * @author wsh
     * @date 2020/9/14
     */
    public static Date getLastDayOfMonth(Date date) throws Exception {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int value = cal.getActualMaximum(Calendar.DATE);
        return stringToDate(dateToString(date, MONTH_PATTERN) + "-" + value);
    }

    public static void main(String[] args) throws Exception {
        System.out.println("本周一：" + dateToString(getThisMonday()));
        System.out.println("本周日：" + dateToString(getThisSunday()));
        Date currentCalendar = getCurrentCalendar();
        System.out.println("当前时间：" + dateToString(currentCalendar));
        System.out.println("当前时间+1年：" + dateToString(dateTimeCalculate(currentCalendar, 'y', 1)));
        System.out.println("当前时间-1年：" + dateToString(dateTimeCalculate(currentCalendar, 'y', -1)));
        System.out.println("当前时间+1小时：" + dateToString(dateTimeCalculate(currentCalendar, 'H', 1)));
        System.out.println("当前时间 VS 明年现在：" + dateCompare(currentCalendar, dateTimeCalculate(currentCalendar, 'y', 1)));
        System.out.println("当前时间 VS 去年现在：" + dateCompare(currentCalendar, dateTimeCalculate(currentCalendar, 'y', -1)));
        System.out.println("当前时间与比较日期相距：" + dateBetween(stringToDate("2016-01-01"), currentCalendar) + " 日");
        System.out.println("当前时间：" + getYear(currentCalendar));
        System.out.println("当前时间：" + getMonth(currentCalendar));
        System.out.println("当前时间：" + getDate(currentCalendar));
        System.out.println("当前时间，月的天数：" + getDaysOfMonth(currentCalendar));
        System.out.println("当前时间，年的天数：" + getDaysOfYear(currentCalendar));
        System.out.println("当前时间，月第一天：" + dateToString(getFirstDayOfMonth(currentCalendar)));
        System.out.println("当前时间，月最后一天：" + dateToString(getLastDayOfMonth(currentCalendar)));
    }
}
